package com.zzw.service;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.zzw.model.*;
import com.zzw.utils.error.CommonError;
import com.zzw.utils.exception.AppCommonException;
import com.zzw.utils.opfile.FileStreamOperation;

import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * @author zzw
 * @version 1.0
 * @title StudentManagerServiceImpl
 * @description 学生管理服务实现类
 * @datetime 2022-12-28 8:18 下午
 */
public class StudentManagerServiceImpl implements StudentManagerService {

    private static String filePath;

    static {
        // 读取的文件是 target/classes/students.txt
        URL resource = StudentManagerServiceImpl.class.getResource("/students.txt");
        if (resource == null) {
            throw new AppCommonException(CommonError.SYSTEM_ERROR, "找不到资源文件 students.txt");
        }

        // 打包jar后文件在内部，无法访问. 只能通过 stream 方式读取文件内容
        filePath = resource.getFile();
        File file = new File(filePath);
        if (!file.exists()) {
            file = new File("./students.txt");
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    throw new AppCommonException(CommonError.SYSTEM_ERROR, "创建 students.txt 文件失败");
                }
            }
            filePath = file.getAbsolutePath();
        }
    }

    /**
     * ID 自增器
     */
    private static final AtomicLong atomicLong = new AtomicLong();

    @Override
    public boolean addStudent(BaseStudent request) {
        checkParams(request.getStuNo(), request.getStuName());
        StuSexEnum sexEnum = StuSexEnum.findByCode(request.getStuSex());

        if (Objects.isNull(sexEnum)) {
            throw new AppCommonException(CommonError.ILLEGAL_ARGUMENT);
        }

        List<StudentDO> studentDOList = FileStreamOperation.readInfosFromFile(filePath);
        if (CollectionUtils.isNotEmpty(studentDOList) &&
                studentDOList.stream().anyMatch(a -> existsStudent(a, request.getStuNo()))) {
            throw new AppCommonException(CommonError.DATA_EXIST);
        }

        StudentDO studentDo = new StudentDO();
        studentDo.setStudentName(request.getStuName());
        studentDo.setStudentSex(sexEnum.getCode());
        studentDo.setStudentNo(request.getStuNo());
        studentDo.setGmtCreate(new Date());
        studentDo.setGmtModified(new Date());
        studentDo.setDel((byte) 0);

        if (CollectionUtils.isNotEmpty(studentDOList)) {
            atomicLong.set(studentDOList.size());
        }
        studentDo.setId(atomicLong.incrementAndGet());

        List<StudentDO> realList = new ArrayList<>(studentDOList);
        realList.add(studentDo);

        return FileStreamOperation.writeInfosToFile(realList, filePath);
    }

    @Override
    public void deleteStudent(String stuNo) {
        checkParams(stuNo);
        List<StudentDO> studentDOList = FileStreamOperation.readInfosFromFile(filePath);
        if (CollectionUtils.isEmpty(studentDOList)) {
            return;
        }

        studentDOList.forEach(f -> {
            if (f.getStudentNo().equals(stuNo)) {
                f.setGmtModified(new Date());
                f.setDel((byte) 1);
            }
        });
        FileStreamOperation.writeInfosToFile(studentDOList, filePath);
    }

    @Override
    public void deleteAll() {
        FileStreamOperation.writeInfosToFile(new ArrayList<>(), filePath);
    }

    @Override
    public Boolean updateStudent(ModifyStuRequest request) {
        return false;
    }

    @Override
    public QueryStuResponse queryStudent(String stuNo) {
        checkParams(stuNo);

        List<StudentDO> stuResults = FileStreamOperation.readInfosFromFile(filePath);
        if (CollectionUtils.isEmpty(stuResults)) {
            return null;
        }

        List<StudentDO> filterResult = stuResults.stream().filter(s -> existsStudent(s, stuNo)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(filterResult)) {
            return null;
        }

        return convert(filterResult.get(0));
    }

    @Override
    public List<QueryStuResponse> queryAllStudent(int pageNo, int pageSize) {
        if (pageNo <= 0 || pageSize <= 0) {
            throw new AppCommonException(CommonError.ILLEGAL_ARGUMENT);
        }

        List<StudentDO> stuResults = FileStreamOperation.readInfosFromFile(filePath);
        if (CollectionUtils.isEmpty(stuResults)) {
            return new ArrayList<>();
        }

        // 分页处理
        List<StudentDO> pagedList;
        if (pageNo == 1) {
            pagedList = stuResults.stream().filter(s -> 0 == s.getDel()).limit(pageSize).collect(Collectors.toList());
        } else {
            long skipNum = (long) (pageNo - 1) * pageSize;
            pagedList = stuResults.stream().filter(s -> 0 == s.getDel())
                    .skip(skipNum).limit(pageSize).collect(Collectors.toList());
        }
        return convertList(pagedList);
    }

    /**
     * 通过学号判断学生是否存储
     *
     * @param studentDO 学生对象
     * @param stuNo     学号
     * @return 是否存在. true-是, false-否
     */
    private boolean existsStudent(StudentDO studentDO, String stuNo) {
        return stuNo.equals(studentDO.getStudentNo()) && 0 == studentDO.getDel();
    }

    /**
     * 学生信息实体类转换器
     *
     * @param studentDO 学生对象
     * @return 学生信息结果
     */
    private QueryStuResponse convert(StudentDO studentDO) {
        if (Objects.isNull(studentDO)) {
            return null;
        }

        QueryStuResponse queryStuResponse = new QueryStuResponse();
        queryStuResponse.setStuNo(studentDO.getStudentNo());
        queryStuResponse.setStuName(studentDO.getStudentName());
        queryStuResponse.setId(studentDO.getId());

        StuSexEnum sexEnum = Optional.ofNullable(StuSexEnum.findByCode(studentDO.getStudentSex())).orElse(StuSexEnum.N);
        queryStuResponse.setStuSex(sexEnum.getDesc());

        return queryStuResponse;
    }

    private List<QueryStuResponse> convertList(List<StudentDO> studentDOList) {
        List<QueryStuResponse> stuResultList = new ArrayList<>();
        if (CollectionUtils.isEmpty(studentDOList)) {
            return stuResultList;
        }

        studentDOList.forEach(f -> stuResultList.add(convert(f)));

        return stuResultList;
    }

    /**
     * 多参数校验
     *
     * @param args 多参数
     */
    private void checkParams(String... args) {
        for (String arg : args) {
            if (StringUtils.isEmpty(arg)) {
                throw new AppCommonException(CommonError.ILLEGAL_ARGUMENT);
            }
        }
    }
}
